Skip to content

[LWD] feat(desktop): upgrade analytics consent QA screen - #20266

Merged
tonykhaov merged 2 commits into
developfrom
feat/desktop-LIVE-29592-analytics-consent-qa
Aug 5, 2026
Merged

[LWD] feat(desktop): upgrade analytics consent QA screen#20266
tonykhaov merged 2 commits into
developfrom
feat/desktop-LIVE-29592-analytics-consent-qa

Conversation

@tonykhaov

@tonykhaov tonykhaov commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

✅ Checklist

  • npx changeset was attached.
  • Covered by automatic tests. View-model tests cover quiet/major/minor/no-consent/reset/flag-off/preview-in-place paths; UI layout not snapshot-tested.
  • Impact of the changes:
    - Developer → Analytics consent QA screen (desktop Settings → Developer)
    - Dialog preview mounts in place on desktop QA screen (no portfolio navigation)
    - Collapses deprecated DANGEROUSLY_* QA settings helpers into setAnalyticsConsentInfo

📝 Description

Upgrade the desktop analytics consent QA debug screen to scenario parity with mobile (scenario groups, inspector fields, verdicts, preview-in-place via forceOffer).

Depends on shared inspector helper in #20330.

debug.desktop.mp4

❓ Context


🧐 Checklist for the PR Reviewers

  • The code aligns with the requirements described in the linked JIRA or GitHub issue.
  • The PR description clearly documents the changes made and explains any technical trade-offs or design decisions.
  • There are no undocumented trade-offs, technical debt, or maintainability issues.
  • The PR has been tested thoroughly, and any potential edge cases have been considered and handled.
  • Any new dependencies have been justified and documented.
  • Performance considerations have been taken into account. (changes have been profiled or benchmarked if necessary)

Copilot AI lite review requested due to automatic review settings July 31, 2026 07:00
@live-github-bot live-github-bot Bot added desktop Has changes in LLD translations Translation files have been touched labels Jul 31, 2026
@tonykhaov tonykhaov changed the title feat(desktop): upgrade analytics consent QA screen (LIVE-29592) [LWM] feat(desktop): upgrade analytics consent QA screen Jul 31, 2026
@live-github-bot live-github-bot Bot changed the title [LWM] feat(desktop): upgrade analytics consent QA screen [LWD] feat(desktop): upgrade analytics consent QA screen (LIVE-29592) Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Web Tools Build Status

Build Status Deployment
Web Tools Build ⏭️ Skipped
Native Storybook Build ⏭️ Skipped
React Storybook Build ⏭️ Skipped

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Upgrades the Ledger Live Desktop analytics consent QA/debug screen to align with the shared @features/flow-analytics-consent/debug scenarios and inspection helpers, matching the mobile QA tool behavior while keeping the Lumen Web UI.

Changes:

  • Replaces the legacy desktop QA screen logic with a dedicated MVVM-style view-model backed by shared consent-debug helpers (scenarios, verdicts, baselines, reasons).
  • Reworks the desktop QA screen UI to add scenario presets, an Inspect tab (stored state + remote config + user prefs), feature-flag override, and reset.
  • Removes the now-unused analyticsConsentOptInQa i18n keys from all desktop locales and drops deprecated QA-only settings actions.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
apps/ledger-live-desktop/static/i18n/zh/app.json Removes analyticsConsentOptInQa locale strings (hardcoded English copy now used).
apps/ledger-live-desktop/static/i18n/tr/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/th/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/ru/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/pt-BR/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/ko/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/ja/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/fr/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/es/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/en/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/static/i18n/de/app.json Removes analyticsConsentOptInQa locale strings.
apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts New shared-scenarios view-model (verdict/phase, baseline handling, overrides, reset, inspect fields).
apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx Updates the developer settings row to hardcoded copy and uses a Link to open the QA screen.
apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx Rebuilds the QA screen UI (scenario cards + inspect tab + reset + portfolio preview navigation).
apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/tests/useAnalyticsConsentOptInQaViewModel.test.ts Adds view-model tests covering key scenario/reset/flag-off behaviors.
apps/ledger-live-desktop/src/renderer/actions/settings.ts Removes deprecated QA-only analytics consent mutation helpers in favor of normal actions.
.changeset/calm-clouds-debug.md Adds a patch changeset for the desktop package.

@live-github-bot

live-github-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Desktop Bundle Checks

Comparing 57b9efc against d191cdf.

✅ Previous issues have all been fixed.

Mobile Bundle Checks

Comparing 73f80ba against c8d087a.

✅ Previous issues have all been fixed.

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

⚠️ Note: The latest commit (d191cdff05) does not have baseline artifacts. Using commit 87fbff971b for baseline comparison instead. If this seems incorrect, please wait a few minutes and try rerunning the workflow.

Found 7 projects in monorepo, 2 projects with changes.

📊 Quick Summary
Project Total Size Change
desktop-main 2.3 MB 0
desktop-preloader 7.1 KB 0
desktop-renderer 80.7 MB +14.8 KB (0.0%)
desktop-webviewDappPreloader 36.9 KB ❓ 0
desktop-webviewPreloader 200.0 B 0
desktop-workers 36.8 KB 0
mobile 262.0 MB +2.3 KB (0.0%)
📋 Detailed Reports (Click to expand)

📁 desktop-renderer

Path: rsdoctor/desktop-renderer/rsdoctor-data.json

📌 Baseline Commit: 87fbff971b | PR: #20410

Metric Current Baseline Change
📊 Total Size 80.7 MB 80.7 MB +14.8 KB (0.0%)
📄 JavaScript 29.4 MB 29.3 MB +14.8 KB (0.0%)
🎨 CSS 183.2 KB 183.2 KB -6.0 B (-0.0%)
🌐 HTML 1.8 KB 1.8 KB 0
📁 Other Assets 51.2 MB 51.2 MB 0

📦 Download Diff Report: desktop-renderer Bundle Diff

📁 mobile

Path: rsdoctor/mobile/rsdoctor-data.json

📌 Baseline Commit: 87fbff971b | PR: #20410

Metric Current Baseline Change
📊 Total Size 262.0 MB 262.0 MB +2.3 KB (0.0%)
📄 JavaScript 110.7 MB 110.7 MB +1.0 KB (0.0%)
🎨 CSS 0 B 0 B 0
🌐 HTML 0 B 0 B 0
📁 Other Assets 151.3 MB 151.3 MB +1.3 KB (0.0%)

📦 Download Diff Report: mobile Bundle Diff

Generated by Rsdoctor GitHub Action

Copilot AI review requested due to automatic review settings July 31, 2026 09:23
@tonykhaov
tonykhaov force-pushed the chore/analytics-consent-LIVE-29592-remove-consent-validity-days branch from 95dfa06 to ccae87c Compare July 31, 2026 09:23
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 0c7a38e to 77b6694 Compare July 31, 2026 09:24
@github-actions

Copy link
Copy Markdown
Contributor

❌ Action Required: Monitored Files Changed

The following files in monitored folders have been modified:

  • .github/workflows/test-mobile-e2e-reusable.yml

Action Required: Please rebase your branch against develop to ensure consistency:

git rebase origin/develop

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (10)

apps/ledger-live-desktop/static/i18n/de/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Designumschalter",
        "desc" : "Zeigt ein schwebendes Overlay an, mit dem du schnell zwischen Designs umschalten kannst."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/es/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Conmutador de tema",
        "desc" : "Muestra una superposición flotante con la que cambiar de tema rápidamente."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ko/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "테마 토글",
        "desc" : "테마를 빠르게 전환할 수 있도록 플로팅 오버레이를 표시합니다."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/pt-BR/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Alternar tema",
        "desc" : "Exibir botão flutuante para alternar temas rapidamente."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/th/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "ปุ่มสลับธีม",
        "desc" : "แสดงโอเวอร์เลย์แบบลอยตัวเพื่อเปลี่ยนธีมได้อย่างรวดเร็ว"
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/fr/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Sélecteur de thème",
        "desc" : "Affichez une fenêtre flottante pour changer de thème rapidement."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ja/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "テーマ切り替え",
        "desc" : "テーマを素早く切り替えるためのフローティングオーバーレイを表示します。"
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ru/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Переключение темы",
        "desc" : "Отображать плавающий тумблер для быстрого переключения тем."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/tr/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "Tema Butonu",
        "desc" : "Temalar arasında hızlıca geçiş yapmak için bir küçük pencere gösterin."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/zh/app.json:5072

  • Per repo translation workflow guidelines, avoid editing non-English locale files (only apps/ledger-live-desktop/static/i18n/en/app.json should be changed). Please revert this locale change and let the localization sync handle key removals.
      "themeConsole" : {
        "title" : "主题切换",
        "desc" : "显示可快速切换主题的浮动覆盖。"
      },
      "devTools" : {

Copilot AI review requested due to automatic review settings July 31, 2026 09:35
@tonykhaov
tonykhaov force-pushed the chore/analytics-consent-LIVE-29592-remove-consent-validity-days branch from ccae87c to 7821700 Compare July 31, 2026 09:35
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 77b6694 to 1dcc85e Compare July 31, 2026 09:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (10)

apps/ledger-live-desktop/static/i18n/zh/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "主题切换",
        "desc" : "显示可快速切换主题的浮动覆盖。"
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/tr/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Tema Butonu",
        "desc" : "Temalar arasında hızlıca geçiş yapmak için bir küçük pencere gösterin."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/th/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "ปุ่มสลับธีม",
        "desc" : "แสดงโอเวอร์เลย์แบบลอยตัวเพื่อเปลี่ยนธีมได้อย่างรวดเร็ว"
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ru/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Переключение темы",
        "desc" : "Отображать плавающий тумблер для быстрого переключения тем."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/pt-BR/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Alternar tema",
        "desc" : "Exibir botão flutuante para alternar temas rapidamente."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ko/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "테마 토글",
        "desc" : "테마를 빠르게 전환할 수 있도록 플로팅 오버레이를 표시합니다."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/ja/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "テーマ切り替え",
        "desc" : "テーマを素早く切り替えるためのフローティングオーバーレイを表示します。"
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/fr/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Sélecteur de thème",
        "desc" : "Affichez une fenêtre flottante pour changer de thème rapidement."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/es/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Conmutador de tema",
        "desc" : "Muestra una superposición flotante con la que cambiar de tema rápidamente."
      },
      "devTools" : {

apps/ledger-live-desktop/static/i18n/de/app.json:5072

  • This PR edits a non-English locale file. Repo review guidance says desktop translations should only be edited in apps/ledger-live-desktop/static/i18n/en/app.json (see .agents/agents/code-reviewer.md:43), with other locales handled by the localization workflow. Please revert this change (restore the removed key) and keep the functional change in code/hardcoded strings.
      "themeConsole" : {
        "title" : "Designumschalter",
        "desc" : "Zeigt ein schwebendes Overlay an, mit dem du schnell zwischen Designs umschalten kannst."
      },
      "devTools" : {

Copilot AI review requested due to automatic review settings July 31, 2026 09:42
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 1dcc85e to 9058265 Compare July 31, 2026 09:42
@tonykhaov
tonykhaov force-pushed the chore/analytics-consent-LIVE-29592-remove-consent-validity-days branch from 7821700 to ba6c8ba Compare July 31, 2026 09:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (4)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:94

  • formatBareValue currently returns the string "null" for both null and undefined, which makes the inspector output ambiguous (and can hide when a remote param is actually missing). Consider rendering undefined distinctly and falling back when JSON.stringify returns undefined.
export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:25

  • TONE_TEXT is typed as Record<string, string>, which weakens type-safety (any key becomes allowed). Since the keys are meant to match the existing tone union, tighten this to Record<InspectorField["status"]["tone"], string> so missing/extra tones are caught by TypeScript.
const TONE_TEXT: Record<string, string> = {
  error: "text-error",
  warning: "text-warning",
  success: "text-success",
  gray: "text-muted",
};

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:4

  • New Desktop feature code is being added under src/renderer/... (e.g. this new ViewModel hook). Our MVVM architecture guidance states that new code for ledger-live-desktop should go under src/mvvm/ (see .agents/skills/mvvm-architecture/SKILL.md:10-13). Consider moving this QA tool to an MVVM feature folder (or documenting why this is an exception).

This issue also appears on line 91 of the same file.

import { useEffect, useState } from "react";
import { useNavigate } from "react-router";
import { useFeature } from "@features/platform-feature-flags";
import { featureFlagsOverridesSelector, setOverride } from "@shared/feature-flags";

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:3

  • This row switches to Link from react-router, but internal navigation in Settings developer rows is typically handled via useNavigate/onClick (and there are no other Link imports from react-router in the desktop app). To keep navigation patterns consistent (and avoid coupling this row to a specific router component API), consider reverting to an onClick + navigate handler.
import React from "react";
import { Link } from "react-router";
import { Button } from "@ledgerhq/lumen-ui-react";

@tonykhaov

Copy link
Copy Markdown
Contributor Author

Closing — desktop/prune work deferred; stack ends at #20212 for now.

@tonykhaov tonykhaov closed this Aug 3, 2026
@tonykhaov tonykhaov reopened this Aug 3, 2026
Copilot AI review requested due to automatic review settings August 3, 2026 12:36
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 8185884 to 0ca37d4 Compare August 3, 2026 12:36
@tonykhaov
tonykhaov removed request for a team August 3, 2026 12:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (3)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:95

  • formatBareValue currently returns "null" for both null and undefined, and can also return undefined when JSON.stringify yields undefined (e.g. functions). This makes the inspector output ambiguous and breaks the function’s declared string return type.
export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:260

  • consentInfo.consentDate is checked using a truthy condition, so an empty string (""), which is a plausible invalid stored value, would be displayed as consentDate: null in the raw inspector output. Using an explicit null check preserves the actual stored value for debugging.
      raw: consentInfo.consentDate
        ? `consentDate: ${formatBareValue(consentInfo.consentDate)}`
        : "consentDate: null",
      status:

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:26

  • TONE_TEXT is typed as Record<string, string>, which makes it easy to accidentally use unsupported tones without a type error. Since this mapping is meant to cover FieldTone, type it accordingly so missing/extra keys are caught at compile time.
const TONE_TEXT: Record<string, string> = {
  error: "text-error",
  warning: "text-warning",
  success: "text-success",
  gray: "text-muted",
};

@tonykhaov
tonykhaov force-pushed the feat/flow-LIVE-29595-stored-policy-inspector branch from 9d4e5e4 to f2da8aa Compare August 3, 2026 14:42
Copilot AI review requested due to automatic review settings August 3, 2026 14:42
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 0ca37d4 to 4bf3d6d Compare August 3, 2026 14:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:14

  • This row now hardcodes title/description/button label, which regresses i18n and is inconsistent with other Developer settings rows that use react-i18next (e.g. OpenDevToolsRow.tsx:16-22 uses t("settings.developer.*")). Consider restoring useTranslation() + translation keys (and keeping the per-locale entries) so the Settings UI remains localized.
    <SettingsSectionRow
      title="Analytics consent QA"
      desc="Policy bumps, consent state, drawer preview"
    >
      <Button asChild size="sm" appearance="accent">
        <Link to="/settings/developer/analytics-consent-opt-in-qa">Open</Link>
      </Button>

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:95

  • formatBareValue currently prints "null" for both null and undefined, which makes the inspector's raw values ambiguous (missing param vs explicitly null). Showing "undefined" for undefined would make QA/debug output clearer and avoid misleading reads.
export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

@tonykhaov
tonykhaov force-pushed the feat/flow-LIVE-29595-stored-policy-inspector branch from f2da8aa to a009c3e Compare August 4, 2026 08:37
@tonykhaov
tonykhaov force-pushed the feat/desktop-LIVE-29592-analytics-consent-qa branch from 4bf3d6d to a71c587 Compare August 4, 2026 08:38
@tonykhaov tonykhaov changed the title [LWD] feat(desktop): upgrade analytics consent QA screen (LIVE-29592) [LWD] feat(desktop): upgrade analytics consent QA screen Aug 4, 2026
Copilot AI review requested due to automatic review settings August 4, 2026 08:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (5)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:100

  • This screen introduces several user-visible strings as hardcoded English (e.g., header/title/section labels). Since the PR also removes the existing i18n keys, this QA screen will no longer be localized in non-English locales. Even for developer tools, keeping strings behind i18n keys avoids regressions when running the app in other locales.
        <div className="flex min-w-0 justify-start">
          <Button size="sm" appearance="no-background" onClick={vm.onBack} icon={ArrowLeft}>
            Back
          </Button>
        </div>
        <span className="heading-2-semi-bold max-w-[min(100vw-8rem,28rem)] text-center text-base">
          Analytics consent QA
        </span>
        <div aria-hidden className="min-w-0" />

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:95

  • formatBareValue returns the string "null" for both null and undefined, which makes the inspector output misleading (e.g., an absent policyVersion will render as null). Distinguishing undefined helps QA interpret whether a value is missing vs explicitly cleared.
export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:26

  • TONE_TEXT is typed as Record<string, string>, which hides missing/extra tone keys and forces a runtime fallback later. Since the tones are a closed set, it’s safer to type this map against the ViewModel’s headlineTone union so TS enforces completeness.

This issue also appears on line 92 of the same file.

const TONE_TEXT: Record<string, string> = {
  error: "text-error",
  warning: "text-warning",
  success: "text-success",
  gray: "text-muted",
};

apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts:96

  • PR description mentions previewing the dialog “via forceOffer”, but there’s no forceOffer mechanism in the codebase (and the implementation here instead removes the route-focus guard entirely). If the intent is to keep the dialog restricted to Portfolio in production, consider adding an explicit override (e.g., a forceOffer param/prop used only by the QA screen) rather than broadening the default behavior for all mounts.
  useEffect(() => {
    if (!shouldOffer) {
      setPhase(current => {
        if (current !== "closed") {
          track("drawer_closed", dialogClosedPayload);
        }
        return "closed";
      });
      return;
    }
    setPhase(current => {
      if (current === "preferences") return current;
      return resolveAnalyticsConsentPhase(current, decision, shareAnalytics);
    });
  }, [shouldOffer, decision, shareAnalytics]);

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:14

  • This dev-tool row is now hardcoded in English (and the corresponding i18n keys were removed). That makes the Settings → Developer menu inconsistent with the rest of the app’s i18n and removes previously available translations for non-English locales. Consider restoring react-i18next usage here (and reintroducing the removed settings.developer.analyticsConsentOptInQa.* keys, or replacing them with new keys) so the title/description and button label remain localized.
    <SettingsSectionRow
      title="Analytics consent QA"
      desc="Policy bumps, consent state, drawer preview"
    >
      <Button asChild size="sm" appearance="accent">
        <Link to="/settings/developer/analytics-consent-opt-in-qa">Open</Link>
      </Button>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:259

  • raw uses a truthy check on consentInfo.consentDate, so an empty string (invalid but possible persisted value) would be displayed as consentDate: null, losing debugging signal. Use an explicit null check so invalid strings remain visible.
          enabled,
          params: feature?.params ?? {},
        },

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/static/i18n/zh/app.json:5075

  • Repo translation guideline: desktop PRs should only edit apps/ledger-live-desktop/static/i18n/en/app.json (other locales are managed separately). This PR removes settings.developer.analyticsConsentOptInQa from multiple non-en locale files (including this one), which should be reverted; keep the change in en/app.json only (or keep the key in code).
      "themeConsole" : {
        "title" : "主题切换",
        "desc" : "显示可快速切换主题的浮动覆盖。"
      },
      "devTools" : {
        "rowTitle" : "开发工具",
        "rowDesc" : "打开 DevTools 开发工具界面(功能标志和开发者工具面板)。"
      },

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:5

  • New Desktop feature/UI logic is being introduced under src/renderer/screens/... (this new ViewModel file). Per the repo MVVM standard, new screens/components/hooks for ledger-live-desktop should be added under apps/ledger-live-desktop/src/mvvm/ (FeatureName/{screens,hooks,components,utils}) and the view should receive data via props from a ViewModel hook.
import { useEffect, useState } from "react";
import { useNavigate } from "react-router";
import { useFeature } from "@features/platform-feature-flags";
import { featureFlagsOverridesSelector, setOverride } from "@shared/feature-flags";
import {

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (4)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:14

  • This Settings row was switched from i18n keys to hard-coded English strings, and the related translation entries were removed from multiple locales. That makes the Developer settings screen inconsistent with the rest of Settings rows (which use react-i18next) and regresses localization for non-English users.
    <SettingsSectionRow
      title="Analytics consent QA"
      desc="Policy bumps, consent state, drawer preview"
    >
      <Button asChild size="sm" appearance="accent">
        <Link to="/settings/developer/analytics-consent-opt-in-qa">Open</Link>
      </Button>

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:182

  • This PR introduces a new ViewModel hook under src/renderer/screens/... rather than the src/mvvm/ structure used for new desktop feature code. If we want to follow the MVVM migration rules, this logic should live under src/mvvm/features/... with the corresponding View component consuming it via props.
export function useAnalyticsConsentOptInQaViewModel() {
  const navigate = useNavigate();
  const dispatch = useDispatch();
  const feature = useFeature(FLAG_KEY);
  const rawPolicyVersion = feature?.params?.policyVersion;

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:91

  • PR description mentions preview-in-place via a forceOffer mechanism, but the QA screen preview currently just mounts <AnalyticsConsentDialog /> normally. Since the dialog still relies on shouldOffer, this is not a forced preview API. Either update the PR description to match the implementation, or implement an explicit override prop/API if forced preview is required.
    <Box grow shrink className="p-8 pb-16">
      {vm.isPreviewMounted ? <AnalyticsConsentDialog key={vm.previewKey} /> : null}
      <header className="mb-14 grid grid-cols-[1fr_auto_1fr] items-center gap-x-3 py-6">

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/AnalyticsConsentOptInDevScreen.tsx:152

  • SegmentedControl's onSelectedChange callback provides a string, but passing the React state setter directly weakens type-safety (it can accept values outside the intended "scenarios" | "inspect" union). Wrap it with a narrow cast handler (similar to other usages like MarketCategoryBar).
              <SegmentedControl
                selectedValue={vm.tab}
                onSelectedChange={vm.setTab}
                tabLayout="fit"
                aria-label="Analytics consent QA sections"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:14

  • This row switches from the established pattern (Button + useNavigate) to Link imported from react-router. There are no other occurrences of import { Link } from "react-router" in the desktop codebase, while other QA rows (e.g. LargeScreenUpsellDevTool/index.tsx:12-23) use useNavigate. To avoid a potentially invalid import and keep navigation consistent, use useNavigate here as well.
import React from "react";
import { Link } from "react-router";
import { Button } from "@ledgerhq/lumen-ui-react";
import { SettingsSectionRow } from "~/renderer/screens/settings/SettingsSection";

export default function AnalyticsConsentOptInDevTool() {
  return (
    <SettingsSectionRow
      title="Analytics consent QA"
      desc="Policy bumps, consent state, drawer preview"
    >
      <Button asChild size="sm" appearance="accent">
        <Link to="/settings/developer/analytics-consent-opt-in-qa">Open</Link>
      </Button>

apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts:96

  • Removing the route-focus guard means drawer_closed is no longer tracked when the dialog is implicitly dismissed by navigation/unmount while still open (previously covered by the deleted tests). If this event is still expected for analytics completeness, consider adding an unmount/route-change close path (or cleanup) that emits drawer_closed when phase !== "closed".
  useEffect(() => {
    if (!shouldOffer) {
      setPhase(current => {
        if (current !== "closed") {
          track("drawer_closed", dialogClosedPayload);
        }
        return "closed";
      });
      return;
    }
    setPhase(current => {
      if (current === "preferences") return current;
      return resolveAnalyticsConsentPhase(current, decision, shareAnalytics);
    });
  }, [shouldOffer, decision, shareAnalytics]);

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

apps/ledger-live-desktop/static/i18n/en/app.json:5042

  • The analyticsConsentOptInQa translation block was removed from the English source file, but it still exists in other locale JSONs (e.g. static/i18n/fr/app.json). If the intent is to remove this row’s translation keys, consider removing the same block from the other locales too to avoid keeping stale/unused translations.
      "themeConsole": {
        "title": "Theme Toggle",
        "desc": "Display a floating overlay to quickly switch themes."
      },
      "devTools": {
        "rowTitle": "DevTools",
        "rowDesc": "Open the DevTools shell (feature flags and dev tools panel)."
      },

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/index.tsx:14

  • This row was switched from i18n keys to hardcoded English strings. In the Developer settings section, other rows consistently use react-i18next keys (e.g. apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/index.tsx:57+), so this change breaks localization consistency and makes the QA row non-translatable.
    <SettingsSectionRow
      title="Analytics consent QA"
      desc="Policy bumps, consent state, drawer preview"
    >
      <Button asChild size="sm" appearance="accent">
        <Link to="/settings/developer/analytics-consent-opt-in-qa">Open</Link>
      </Button>

apps/ledger-live-desktop/src/mvvm/features/AnalyticsConsentDialog/hooks/useAnalyticsConsentDialogViewModel.ts:96

  • With the portfolio-route focus check removed, drawer_closed is only tracked when the view model explicitly transitions to closed. If the dialog unmounts while open (navigation, or QA preview being unmounted), the close event won’t be tracked. Adding an unmount cleanup to emit drawer_closed when phase !== "closed" preserves the previous behavior without reintroducing route coupling.
  useEffect(() => {
    if (!shouldOffer) {
      setPhase(current => {
        if (current !== "closed") {
          track("drawer_closed", dialogClosedPayload);
        }
        return "closed";
      });
      return;
    }
    setPhase(current => {
      if (current === "preferences") return current;
      return resolveAnalyticsConsentPhase(current, decision, shareAnalytics);
    });
  }, [shouldOffer, decision, shareAnalytics]);

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:162

  • This uses a truthiness check for consentInfo.consentDate, so an empty string (or any other falsy string) would be displayed as consentDate: null, hiding the real raw value. Since this is an inspector, it should distinguish null from other invalid string values.
        raw: consentInfo.consentDate
          ? `consentDate: ${formatBareValue(consentInfo.consentDate)}`
          : "consentDate: null",
        status: consentDateStatus,

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:98

  • formatBareValue currently returns "null" for both null and undefined, which makes the inspector raw values misleading (e.g. an actually-undefined remote policyVersion will be shown as null).

This issue also appears on line 159 of the same file.

export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/src/renderer/actions/settings.ts:76

  • setAnalyticsConsentInfo now accepts Partial<AnalyticsConsentInfo>, but the reducer merges the payload with a spread ({ ...state.analyticsConsentInfo, ...payload }). With exactOptionalPropertyTypes not enabled for the desktop app, callers can accidentally pass undefined fields (e.g. { consentDate: undefined }), which would overwrite previously valid values and break invariants (these fields are expected to be string | null). Since all current call sites provide both fields, consider keeping this action helper strict (AnalyticsConsentInfo) and rely on callers to pass the existing value when they want to keep it unchanged (as the QA view-model already does).
export const setAnalyticsConsentInfo = (info: Partial<AnalyticsConsentInfo>) =>
  saveAnalyticsConsentInfo(info);

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:98

  • formatBareValue currently renders undefined as "null", which can mislead when inspecting raw remote-config values (e.g. missing policyVersion). It also doesn't guard against values that stringify to undefined (e.g. Symbol) or throw (BigInt). Consider distinguishing undefined explicitly and falling back to String(value) when JSON serialization isn't usable.
export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:5

  • This new QA screen ViewModel is introduced under apps/ledger-live-desktop/src/renderer/..., but the repo MVVM guidelines state that new desktop code should live under apps/ledger-live-desktop/src/mvvm/ (see .agents/skills/mvvm-architecture/SKILL.md:10-13). To stay aligned with the migration, this hook (and ideally the QA screen) should be moved into an appropriate src/mvvm/features/... folder (with a View/Container split if needed) rather than adding more new code in the legacy renderer/ tree.
import { useEffect, useState } from "react";
import { useNavigate } from "react-router";
import { useFeature } from "@features/platform-feature-flags";
import { featureFlagsOverridesSelector, setOverride } from "@shared/feature-flags";
import {

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (2)

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:162

  • raw consent-date display uses a truthy check, so an invalid-but-present value like an empty string will be shown as consentDate: null, which misrepresents what is actually stored. Use an explicit null check so invalid strings still display their raw value.
        raw: consentInfo.consentDate
          ? `consentDate: ${formatBareValue(consentInfo.consentDate)}`
          : "consentDate: null",
        status: consentDateStatus,

apps/ledger-live-desktop/src/renderer/screens/settings/sections/Developer/AnalyticsConsentOptInDevTool/useAnalyticsConsentOptInQaViewModel.ts:98

  • formatBareValue currently returns the string "null" for both null and undefined, which hides the distinction in the inspector output (and can mislead debugging). It’s safer to render undefined explicitly and fall back when JSON.stringify throws.

This issue also appears on line 159 of the same file.

export function formatBareValue(value: unknown): string {
  if (value === null || value === undefined) return "null";
  return JSON.stringify(value);
}

@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
69.7% Coverage on New Code (required ≥ 80%)
4.0% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop Has changes in LLD translations Translation files have been touched

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants